From 51fc3825825f1bcaa6c76130c3f86921a7887101 Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Thu, 23 Apr 2020 18:01:40 +0100 Subject: [PATCH] Notify accessibility state changes from GtkWidget Piggybacking on blanket GObject::notify is not very efficient. --- gtk/a11y/gtkwidgetaccessible.c | 184 ++++++++++++++------------ gtk/a11y/gtkwidgetaccessibleprivate.h | 14 +- gtk/gtkwidget.c | 21 +++ 3 files changed, 133 insertions(+), 86 deletions(-) diff --git a/gtk/a11y/gtkwidgetaccessible.c b/gtk/a11y/gtkwidgetaccessible.c index ddd16a0cd6..5fc9f7f09e 100644 --- a/gtk/a11y/gtkwidgetaccessible.c +++ b/gtk/a11y/gtkwidgetaccessible.c @@ -38,20 +38,6 @@ G_DEFINE_TYPE_WITH_CODE (GtkWidgetAccessible, gtk_widget_accessible, GTK_TYPE_AC G_ADD_PRIVATE (GtkWidgetAccessible) G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT, atk_component_interface_init)) -/* Translate GtkWidget property change notification to the notify_gtk vfunc */ -static void -notify_cb (GObject *obj, - GParamSpec *pspec) -{ - GtkWidgetAccessible *widget; - GtkWidgetAccessibleClass *klass; - - widget = GTK_WIDGET_ACCESSIBLE (gtk_widget_get_accessible (GTK_WIDGET (obj))); - klass = GTK_WIDGET_ACCESSIBLE_GET_CLASS (widget); - if (klass->notify_gtk) - klass->notify_gtk (obj, pspec); -} - /*< private > * gtk_widget_accessible_update_bounds: * @self: a #GtkWidgetAccessible @@ -95,18 +81,104 @@ gtk_widget_accessible_notify_showing (GtkWidgetAccessible *self) gtk_widget_get_mapped (widget)); } +void +gtk_widget_accessible_notify_tooltip (GtkWidgetAccessible *self) +{ + g_return_if_fail (GTK_IS_WIDGET_ACCESSIBLE (self)); + + GtkWidget *widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (self)); + + atk_object_notify_state_change (ATK_OBJECT (self), + ATK_STATE_HAS_TOOLTIP, + gtk_widget_get_has_tooltip (widget)); +} + +void +gtk_widget_accessible_notify_visible (GtkWidgetAccessible *self) +{ + g_return_if_fail (GTK_IS_WIDGET_ACCESSIBLE (self)); + + GtkWidget *widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (self)); + + atk_object_notify_state_change (ATK_OBJECT (self), + ATK_STATE_VISIBLE, + gtk_widget_get_visible (widget)); +} + +void +gtk_widget_accessible_notify_sensitive (GtkWidgetAccessible *self) +{ + g_return_if_fail (GTK_IS_WIDGET_ACCESSIBLE (self)); + + GtkWidget *widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (self)); + gboolean is_sensitive = gtk_widget_get_sensitive (widget); + + atk_object_notify_state_change (ATK_OBJECT (self), + ATK_STATE_SENSITIVE, + is_sensitive); + atk_object_notify_state_change (ATK_OBJECT (self), + ATK_STATE_ENABLED, + is_sensitive); +} + +void +gtk_widget_accessible_notify_focus (GtkWidgetAccessible *self) +{ + g_return_if_fail (GTK_IS_WIDGET_ACCESSIBLE (self)); + + GtkWidget *widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (self)); + + atk_object_notify_state_change (ATK_OBJECT (self), + ATK_STATE_FOCUSED, + gtk_widget_has_focus (widget)); +} + +void +gtk_widget_accessible_notify_orientation (GtkWidgetAccessible *self) +{ + g_return_if_fail (GTK_IS_WIDGET_ACCESSIBLE (self)); + + GtkWidget *widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (self)); + + if (GTK_IS_ORIENTABLE (widget)) + { + GtkOrientable *orientable = GTK_ORIENTABLE (widget); + GtkOrientation orientation = gtk_orientable_get_orientation (orientable); + + atk_object_notify_state_change (ATK_OBJECT (self), + ATK_STATE_HORIZONTAL, + orientation == GTK_ORIENTATION_HORIZONTAL); + atk_object_notify_state_change (ATK_OBJECT (self), + ATK_STATE_VERTICAL, + orientation == GTK_ORIENTATION_VERTICAL); + } +} + static void -gtk_widget_accessible_initialize (AtkObject *obj, - gpointer data) +notify_cb (GObject *gobject, + GParamSpec *pspec, + gpointer user_data) { - GtkWidget *widget; + GtkWidget *widget = GTK_WIDGET (gobject); + GtkWidgetAccessible *self = user_data; - widget = GTK_WIDGET (data); + GTK_WIDGET_ACCESSIBLE_GET_CLASS (self)->notify_gtk (G_OBJECT (widget), pspec); +} - g_signal_connect (widget, "notify", G_CALLBACK (notify_cb), NULL); +static void +gtk_widget_accessible_initialize (AtkObject *object, + gpointer data) +{ + GtkWidgetAccessible *self = GTK_WIDGET_ACCESSIBLE (object); + GtkWidget *widget = data; - GTK_WIDGET_ACCESSIBLE (obj)->priv->layer = ATK_LAYER_WIDGET; - obj->role = ATK_ROLE_UNKNOWN; + self->priv->layer = ATK_LAYER_WIDGET; + object->role = ATK_ROLE_UNKNOWN; + + /* XXX: This will go away once we move all GtkWidgetAccessibleClass.notify_gtk() + * implementations to explicit API on their respective classes + */ + g_signal_connect (widget, "notify", G_CALLBACK (notify_cb), self); } static const char * @@ -437,69 +509,6 @@ gtk_widget_accessible_get_index_in_parent (AtkObject *accessible) return index; } -/* This function is the default implementation for the notify_gtk - * vfunc which gets called when a property changes value on the - * GtkWidget associated with a GtkWidgetAccessible. It constructs - * an AtkPropertyValues structure and emits a “property_changed” - * signal which causes the user specified AtkPropertyChangeHandler - * to be called. - */ -static void -gtk_widget_accessible_notify_gtk (GObject *obj, - GParamSpec *pspec) -{ - GtkWidget* widget = GTK_WIDGET (obj); - AtkObject* atk_obj = gtk_widget_get_accessible (widget); - AtkState state; - gboolean value; - - if (g_strcmp0 (pspec->name, "has-focus") == 0) - { - state = ATK_STATE_FOCUSED; - value = gtk_widget_has_focus (widget); - } - else if (g_strcmp0 (pspec->name, "tooltip-text") == 0) - { - if (atk_obj->description == NULL) - g_object_notify (G_OBJECT (atk_obj), "accessible-description"); - return; - } - else if (g_strcmp0 (pspec->name, "visible") == 0) - { - state = ATK_STATE_VISIBLE; - value = gtk_widget_get_visible (widget); - } - else if (g_strcmp0 (pspec->name, "sensitive") == 0) - { - state = ATK_STATE_SENSITIVE; - value = gtk_widget_get_sensitive (widget); - } - else if (g_strcmp0 (pspec->name, "orientation") == 0 && - GTK_IS_ORIENTABLE (widget)) - { - GtkOrientable *orientable; - - orientable = GTK_ORIENTABLE (widget); - - state = ATK_STATE_HORIZONTAL; - value = (gtk_orientable_get_orientation (orientable) == GTK_ORIENTATION_HORIZONTAL); - } - else if (g_strcmp0 (pspec->name, "has-tooltip") == 0) - { - state = ATK_STATE_HAS_TOOLTIP; - value = gtk_widget_get_has_tooltip (widget); - } - else - return; - - atk_object_notify_state_change (atk_obj, state, value); - if (state == ATK_STATE_SENSITIVE) - atk_object_notify_state_change (atk_obj, ATK_STATE_ENABLED, value); - - if (state == ATK_STATE_HORIZONTAL) - atk_object_notify_state_change (atk_obj, ATK_STATE_VERTICAL, !value); -} - static AtkAttributeSet * gtk_widget_accessible_get_attributes (AtkObject *obj) { @@ -550,6 +559,13 @@ gtk_widget_accessible_ref_child (AtkObject *object, return NULL; } +static void +gtk_widget_accessible_notify_gtk (GObject *gobject, + GParamSpec *pspec) +{ + /* Empty, used to chain up safely */ +} + static void gtk_widget_accessible_class_init (GtkWidgetAccessibleClass *klass) { diff --git a/gtk/a11y/gtkwidgetaccessibleprivate.h b/gtk/a11y/gtkwidgetaccessibleprivate.h index e1f210bb35..e60abcb337 100644 --- a/gtk/a11y/gtkwidgetaccessibleprivate.h +++ b/gtk/a11y/gtkwidgetaccessibleprivate.h @@ -25,9 +25,19 @@ G_BEGIN_DECLS void _gtk_widget_accessible_set_layer (GtkWidgetAccessible *accessible, AtkLayer layer); -void gtk_widget_accessible_update_bounds (GtkWidgetAccessible *self); +void gtk_widget_accessible_update_bounds (GtkWidgetAccessible *self); -void gtk_widget_accessible_notify_showing (GtkWidgetAccessible *self); +void gtk_widget_accessible_notify_showing (GtkWidgetAccessible *self); + +void gtk_widget_accessible_notify_tooltip (GtkWidgetAccessible *self); + +void gtk_widget_accessible_notify_visible (GtkWidgetAccessible *self); + +void gtk_widget_accessible_notify_sensitive (GtkWidgetAccessible *self); + +void gtk_widget_accessible_notify_focus (GtkWidgetAccessible *self); + +void gtk_widget_accessible_notify_orientation (GtkWidgetAccessible *self); G_END_DECLS diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index a56c55d06d..960232e942 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -2634,6 +2634,9 @@ gtk_widget_show (GtkWidget *widget) g_signal_emit (widget, widget_signals[SHOW], 0); g_object_notify_by_pspec (G_OBJECT (widget), widget_props[PROP_VISIBLE]); + if (priv->accessible != NULL) + gtk_widget_accessible_notify_visible (GTK_WIDGET_ACCESSIBLE (priv->accessible)); + gtk_widget_pop_verify_invariants (widget); g_object_unref (widget); } @@ -2694,6 +2697,9 @@ gtk_widget_hide (GtkWidget *widget) g_signal_emit (widget, widget_signals[HIDE], 0); g_object_notify_by_pspec (G_OBJECT (widget), widget_props[PROP_VISIBLE]); + if (priv->accessible != NULL) + gtk_widget_accessible_notify_visible (GTK_WIDGET_ACCESSIBLE (priv->accessible)); + parent = gtk_widget_get_parent (widget); if (parent) gtk_widget_queue_resize (parent); @@ -5687,6 +5693,9 @@ gtk_widget_set_sensitive (GtkWidget *widget, update_cursor_on_state_change (widget); } + if (priv->accessible != NULL) + gtk_widget_accessible_notify_sensitive (GTK_WIDGET_ACCESSIBLE (priv->accessible)); + g_object_notify_by_pspec (G_OBJECT (widget), widget_props[PROP_SENSITIVE]); } @@ -9779,6 +9788,9 @@ gtk_widget_set_has_tooltip (GtkWidget *widget, { priv->has_tooltip = has_tooltip; + if (priv->accessible != NULL) + gtk_widget_accessible_notify_tooltip (GTK_WIDGET_ACCESSIBLE (priv->accessible)); + g_object_notify_by_pspec (G_OBJECT (widget), widget_props[PROP_HAS_TOOLTIP]); } } @@ -10375,6 +10387,10 @@ gtk_widget_set_has_focus (GtkWidget *widget, return; priv->has_focus = has_focus; + + if (priv->accessible != NULL) + gtk_widget_accessible_notify_focus (GTK_WIDGET_ACCESSIBLE (priv->accessible)); + g_object_notify_by_pspec (G_OBJECT (widget), widget_props[PROP_HAS_FOCUS]); } @@ -12787,6 +12803,8 @@ void gtk_widget_update_orientation (GtkWidget *widget, GtkOrientation orientation) { + GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); + g_return_if_fail (GTK_IS_WIDGET (widget)); if (orientation == GTK_ORIENTATION_HORIZONTAL) @@ -12799,4 +12817,7 @@ gtk_widget_update_orientation (GtkWidget *widget, gtk_widget_add_css_class (widget, GTK_STYLE_CLASS_VERTICAL); gtk_widget_remove_css_class (widget, GTK_STYLE_CLASS_HORIZONTAL); } + + if (priv->accessible != NULL) + gtk_widget_accessible_notify_orientation (GTK_WIDGET_ACCESSIBLE (priv->accessible)); } -- 2.30.2